//匹配 {{}}
const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g;

/**
  <div id="app" style="color: red; font-size: 20px;">
    hello {{name}}
    <span class="text" style="color:green">{{age}}</span>
  </div>
 */

//_c()是负责创建元素节点的函数
//_v()是负责创建文本节点的函数
//_s()是负责将{{name}}转化为真实数据_s(name)
function vrender() {
  return `
    _c(
      "div",
      {
        id: "app",
        style: {
          "color": "red",
          "font-size": "20px"
        }
      },
      _v("hello" +_s(name)),
      _c(
        "span",
        {
          "class": "text",
          "style": {
            "color": "green"
          }
        },
        _v(_s(age))
      )
    )
  `
}


//根据AST树数据生成 字符串代码
function generate(el) {
  /**
   * console.log(el);
   * {
   *   tag: "div",
   *   type: 1,
   *   attrs: (2) [{…}, {…}],
   *   children: (2) [{…}, {…}],
   *   parent: Window
   * }
   */

  /**
   * 写法：
   * _c(元素, 属性对象{})
   */

  //处理children里面的属性对象
  let children = getChildren(el);

  //组装字符串
  let code = `_c('${el.tag}',${el.attrs.length > 0 ?
      `${formatProps(el.attrs)}` :
      'undefined'
    }${children ? `,${children}` : ''})`;

  // console.log(code);
  return code;
}

//格式化处理 属性attrs数组
function formatProps(attrs) {
  /**
   * console.log(attrs);
   * [
   *   0: {name: 'id', value: 'app'},
   *   1: {name: 'style', value: 'color: red; font-size: 20px;'}
   * ]
   */
  let attrStr = '';

  for (var i = 0; i < attrs.length; i++) {
    let attr = attrs[i];
    // console.log(attr);
    //{name: 'id', value: 'app'}

    //如果属性是style属性则另外处理
    if (attr.name === 'style') {
      let styleAttrs = {};

      //value: 'color: red; font-size: 20px;'
      //以; 作为分隔符
      attr.value.split(';').map((styleAttr) => {
        //color: red
        //以: 作为分隔符
        let [key, value] = styleAttr.split(':');

        // console.log(key, value);
        //color red / font-size 20px

        styleAttrs[key] = value;
      });

      //将处理分割好的每一项的属性值写入到每一项的属性里(对象)
      attr.value = styleAttrs;

      /**
       * console.log(attr);
       * {
       *   name: "style",
       *   value: {color: ' red', " font-size": ' 20px'}
       * }
       */
    }

    //字符串拼接
    //JSON.stringify(attr.value) 因为attr.value的值对象需要转为字符串
    attrStr += `${attr.name}:${JSON.stringify(attr.value)},`

  }

  // console.log(attrStr);
  //id:"app",style:{"color":" red"," font-size":" 20px"},

  // console.log(`{${attrStr.slice(0, -1)}}`);
  //{id:"app"style:{"color":" red"," font-size":" 20px"}

  //去除最后逗号结尾
  //返回一个对象 里面包裹着去除逗号的属性字符串
  return `{${attrStr.slice(0, -1)}}`;
}

//处理children里面的属性对象
function getChildren(el) {
  /**
   * children: [
   *   0: {type: 3, text: 'hello {{name}}'},
   *   1: {tag: 'span', type: 1, children: Array(1), attrs: Array(2), parent: {…}}
   * ]
   */
  const children = el.children;

  if (children) {
    //遍历children里每一项
    //拼接好每一个就加一个逗号,
    //generateChild(c) 遍历到新的函数并传入遍历到的每一项作为参数
    return children.map(c => generateChild(c)).join(',');
  }

}

//生成子标签内容的元素/文本代码
function generateChild(node) {
  // console.log(node);
  //{type: 3, text: 'hello {{name}}'}
  //{tag: 'span', type: 1, children: Array(1), attrs: Array(2), parent: {…}}

  if (node.type === 1) {
    //如果是元素节点 ，再继续生成code
    return generate(node);
  } else if (node.type === 3) {
    //如果是文本节点 
    let text = node.text;
    // console.log(text);
    //拿到了子标签里所有的文本节点 
    //hello { { name } } 欢迎光临 / {{ age } / hello vue

    //有可能文本标签里只有文本 没有{{}}
    // console.log(defaultTagRE.test(text)); true/false/false
    if (!defaultTagRE.test(text)) {
      // console.log(text);
      //hello {{name}} 欢迎光临
      //没有{{}}只有纯文本 直接匹配文本节点的函数
      return `_v(${JSON.stringify(text)})`;
    }

    let match,
      index,
      //lastIndex 每次全局循环不同的符合正则规则字符串时倒数的索引
      //该属性存放一个整数，它声明的是上一次匹配文本之后的第一个字符的位置
      //每次循环后要重置为0
      lastIndex = defaultTagRE.lastIndex = 0,
      //把每次截取出来的结果都存放在textArr里
      textArr = [];

    //遍历当前text
    //defaultTagRE.exec(text) 捕获text
    while (match = defaultTagRE.exec(text)) {
      /**
       * console.log(match);
       * [
       *   0: "{{name}}",
       *   1: "name",
       *   groups: undefined,
       *   index: 6,
       *   input: "hello {{name}} 欢迎光临",
       *   length: 2
       * ]
       */

      //将每次遍历出来捕获到的文本跟index绑定
      index = match.index;

      //从lastIndex开始截取到index
      //6 > 0
      if (index > lastIndex) {
        // console.log(index, lastIndex); 6, 0
        //hello {{name}} 欢迎光临 {{age}}
        //第一次push: slice(lastIndex, index) => slice(6, 0) => 截取并存入 => ['"hello "']
        textArr.push(JSON.stringify(text.slice(lastIndex, index)));
        // console.log(textArr);
        //['"hello "']
      }

      //第二次push:
      textArr.push(`_s(${match[1].trim()})`);
      // console.log(textArr);
      //['"hello "', '_s(name)']

      // console.log(lastIndex); 0
      //match[0].length => 
      // console.log(match[0].length); 8 / 7
      lastIndex = index + match[0].length;
    }

    //当匹配到第二项时发现后面还有文本内容时
    if (lastIndex < text.length) {
      //第三次push:
      textArr.push(JSON.stringify(text.slice(lastIndex)));
      // console.log(textArr);
      //['"hello "', '_s(name)', '" 欢迎光临"']
    }

    // console.log(`_v(${textArr.join('+')})`);
    //_v("hello "+_s(name)+" 欢迎光临")
    //_v(_s(age))

    return `_v(${textArr.join('+')})`;

  }

}

export {
  generate
}